﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Windows.Input;
using System.Xml.Serialization;

using Action = System.Action;

namespace GaleSong
{
    /// <summary>
    ///     A base bindable class that implemented <see cref="INotifyPropertyChanged" />.
    /// </summary>
    [Serializable]
    public abstract class BindableBase : INotifyPropertyChanged
    {
        #region Field

        #endregion

        #region Property


        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public virtual void NotifyPropertyChanged<TProperty>(Expression<Func<TProperty>> property)
        {
            NotifyPropertyChanged(property.GetName());
        }

        protected void NotifyPropertyChanged<T1, T2>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2)
        {
            NotifyPropertyChanged(expression1);
            NotifyPropertyChanged(expression2);
        }
        protected void NotifyPropertyChanged<T1, T2, T3>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3)
        {
            NotifyPropertyChanged(expression1);
            NotifyPropertyChanged(expression2);
            NotifyPropertyChanged(expression3);
        }
        protected void NotifyPropertyChanged<T1, T2, T3, T4>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3, Expression<Func<T4>> expression4)
        {
            NotifyPropertyChanged(expression1);
            NotifyPropertyChanged(expression2);
            NotifyPropertyChanged(expression3);
            NotifyPropertyChanged(expression4);
        }

        protected bool SetProperty<T>(ref T storage, T value, string propertyName)
        {
            return SetProperty<T>(ref storage, value, propertyName, null);
        }

        protected bool SetProperty<T>(ref T target, T value, string propertyName, Action changedCallback)
        {
            if (CompareValues(target, value))
                return false;
            target = value;
            NotifyPropertyChanged(propertyName, changedCallback);
            return true;
        }

        protected void NotifyPropertyChanged(string propertyName, Action changedCallback)
        {
            if (changedCallback != null)
                changedCallback();
            NotifyPropertyChanged(propertyName);
        }

        static bool CompareValues<T>(T storage, T value)
        {
            return Equals(storage, value);
        }

        #endregion
    }
}